
import { Map, Overlay, View } from "ol"
import type { MapOptions } from "ol/Map"
import TileLayer from "ol/layer/Tile"
import VectorLayer from "ol/layer/Vector"
import { XYZ } from "ol/source"
import VectorSource from "ol/source/Vector"
import { onMounted, onBeforeUnmount, reactive, provide, inject, InjectionKey, MaybeRef, toRefs, unref, toRaw, nextTick, onUnmounted } from "vue"
import type { DrawEvent, Options as DrawOption } from 'ol/interaction/Draw'
import type { Type as DrawType } from 'ol/geom/Geometry'
import type { Options as OverlayOption } from 'ol/Overlay'
import type { Options as SelectOption } from 'ol/interaction/Select'
import Select, { SelectEvent } from 'ol/interaction/Select'
import Draw from "ol/interaction/Draw"
import { isFunction, isString } from '@vue/shared'
import { click } from "ol/events/condition"


class FyMap {


    constructor(){

    }
}

// 获取原始对象
export const toInitial = (obj: MaybeRef) => toRaw(unref(obj))

// 注入map对象的key
export const fyMapInjectionKey = Symbol("fy-map-key") as InjectionKey<{ map: any}>
// 获取注入的map原始对象
export const getMap = () => toRaw(unref(inject(fyMapInjectionKey)))

const key_ = 'b945c29c5388432e34b51b5d824d8157'
const createMap = (opt: MapOptions) => {
    // 地图实例
    const instance = reactive<{map: Map | undefined}>({ map: undefined })

    const test = reactive({ a: 0})
    onMounted(()=>{
        instance.map = new Map(opt)
        test.a = 10
    })
    provide(fyMapInjectionKey, {
        ...toRefs(instance)
    })

    return {
        map: instance
    }
}

export type TianDiTuType = 'vec_w' | 'cia_w'
export const useDianDiTu = (target: string | HTMLElement) => {
    /**
     * 
     * @param type 天地图类型
     * @param key 天地图key
     * @param properties 属性
     * @returns 
     */
    function createTitleLayer(type: TianDiTuType, key: string, properties: { [x: string]: any } = {}) {
        return new TileLayer({
            source: new XYZ({
                url: `http://t0.tianditu.gov.cn/DataServer?T=${type}&x={x}&y={y}&l={z}&tk=${key}`,
                crossOrigin: 'anonymous'
            }),
            properties: {
                name: "tian_di_tu_title_layer",
                ...properties
            }
        })
    }

    const map = createMap({
        target,
        layers: [
            createTitleLayer('vec_w', key_),
            createTitleLayer('cia_w', key_),
        ],
        controls: [], // 不包含任何控制组件
        //视图
        view: new View({
            center: [113.75395, 34.76572],
            zoom: 8,
            projection: "EPSG:4326"
        })
    })


    return {
        map,
        createTitleLayer
    }
}

export type DrawTypes = DrawType | 'None'
export interface FyDrawOption {
    // name
    name: string,
    map: MaybeRef<Map | null>,
    show?: boolean,
    // 绘制结束
    drawend?: (event: DrawEvent, drawLayer: VectorLayer<VectorSource>) => void,
    // Draw 配置
    drawOpt?: DrawOption[],
    // 绘制类型
    drawType: MaybeRef<DrawTypes>
}

/**
 * 绘制
 * @param opt 配置
 * @returns 
 */
export const useDraw = (opt: FyDrawOption) => {
    let map_: Map | null = null
    let show_ = opt.show || true
    const drawLayerName = `draw_${opt.name}`
    
    // 创建一个用于存放要素的矢量图层
    const drawLayer = new VectorLayer({
        source: new VectorSource({
            wrapX: false
        }),
        properties: {
            name: drawLayerName
        }
    })

    
    // 是否已经开始绘制
    const isStarted = () => {
        return !!getMap()?.getInteractions().getArray().find(item => item === draw)
    }
    //  图层是否挂在
    const isLayerMounted = () => !!getMap()?.getLayers().getArray().find((item) => item.get("name") === drawLayerName)
    // 是否已经显示
    const isShowed = () => isLayerMounted() && drawLayer.getVisible()
    
    // 设置 map 地图对象
    const setMap = (map: Map) => map_ = map
    // 获取 map 对象
    const getMap = () => toRaw(unref(opt.map)) || map_
    // 创建一个交互式绘制工具，用于点击选点
    let draw: Draw
    // 画完操作事件
    const drawendEvent = (event: DrawEvent) => opt.drawend?.(event, drawLayer)

    
    // 隐藏图层
    const hide = () => isShowed() && drawLayer.setVisible(false)
    // 显示图层
    const show = () => {
        drawLayer.setVisible(true)
        !isLayerMounted() && getMap()?.addLayer(drawLayer)
    }
    // 清空图层
    const clear = () => drawLayer.getSource()?.clear()

    drawLayer.setVisible(false)
    /**
     * 开始绘制
     * @returns 
     */
    const start = () => {
        const map = getMap()
        if(!map) return;
        if(isStarted()){
            end()
        }
        // 初始化
        const type = unref(opt.drawType)
        if(type === 'None'){
            return
        }
        show_ && show()
        draw = new Draw({
            source: drawLayer.getSource() || undefined,
            type
        })
        // 监听画完操作事件
        opt.drawend && isFunction(opt.drawend) && draw.on('drawend', drawendEvent)
        // 添加交互式绘制工具到地图
        map.addInteraction(draw)
    }
    /**
     * 结束绘制
     * @param map 地图对象
     * @returns Interaction | undefined
     */
    const end = () => getMap()?.removeInteraction(draw)

    onBeforeUnmount(() => {
        if(isStarted()){
            end()
        }
        hide()
    })

    return {
        start,
        end,
        setMap,
        hide,
        show,
        clear
    }
}

export type FyPopupOverlayOption = Omit<OverlayOption, 'element'>


export interface FyPopupOption {
    map: MaybeRef<Map>,
    element: string | HTMLElement,
    overlay?: FyPopupOverlayOption,
    select?: SelectOption,
    selectEventType?: 'change'|'change:active'|'error'|'propertychange'|'select'
    selectListener: (event: SelectEvent) => unknown,
    autoRemove?: boolean
}
export const usePopup = (opt: FyPopupOption) => {
    const { element, selectEventType = 'select',autoRemove = true } = opt

    const overlayOpt = Object.assign({
        positioning: 'bottom-center',
        stopEvent: false,
        id: 'custom_popup_',
        className: 'cverlayClassName',
        offset: [0, -10] // 设置弹窗位置的偏移量
    }, opt.overlay)

    const select = new Select({
        condition: click,
        ...(opt.select || {})
    })
    
    // 覆盖层
    const popupOverlay = new Overlay({
        autoPan: true,
        ...overlayOpt
    })

    nextTick(() => {
        const map_ = unref(opt.map)
        popupOverlay.setElement(isString(element) ? document.getElementById(element) as HTMLElement : element as HTMLElement)
        map_.addInteraction(select)
        map_.addOverlay(popupOverlay)
        select.on(selectEventType as any, opt.selectListener)
    })

    const remove = () => {
        const map_ = toRaw(unref(opt.map))
        select.un(selectEventType as any, opt.selectListener)
        map_.removeInteraction(select)
        map_.removeOverlay(popupOverlay)
    }

    onUnmounted(() => {
        autoRemove && remove()
    })
    
    return {
        overlay:  popupOverlay,
        select,
        remove
    }
}






